/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.ceair.flight.refund.util;

import com.ceair.flight.refund.location.model.SegrpuDO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

/**
 * @author youguilin
 */
public final class RefundUtil {

    private static final Logger LOG = LoggerFactory.getLogger(RefundUtil.class);

    //forbit create new instance
    private RefundUtil() {
    }

    public static Date getDate(Date date, int hour) {
        return getDate(date, Calendar.HOUR_OF_DAY, hour);
    }

    public static Date getDate(Date date, int unit, int hour) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(unit, hour);
        return calendar.getTime();
    }

    /**
     * 计算给定生日的年龄
     *
     * @param birthdayStr format yyyy-MM-dd
     * @return
     */
    public static int getAge(String birthdayStr) {
        try {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            Date birthday = format.parse(birthdayStr);
            Calendar cal = Calendar.getInstance();

            if (cal.before(birthday)) {
//                throw new IllegalArgumentException("The birthday is before Now.");
                LOG.error("the birthday {} is before Now.", birthdayStr);
            }

            int yearNow = cal.get(Calendar.YEAR);
            int monthNow = cal.get(Calendar.MONTH) + 1;
            int dayOfMonthNow = cal.get(Calendar.DAY_OF_MONTH);

            cal.setTime(birthday);
            int yearBirth = cal.get(Calendar.YEAR);
            int monthBirth = cal.get(Calendar.MONTH) + 1;
            int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);

            int age = yearNow - yearBirth + 1;

            if (monthNow <= monthBirth) {
                if (monthNow == monthBirth) {
                    // monthNow==monthBirth
                    if (dayOfMonthNow < dayOfMonthBirth) {
                        age--;
                    }
                } else {
                    // monthNow>monthBirth
                    age--;
                }
            }
            LOG.debug("Birthday {} this year age is {}", birthdayStr, age);
            return age;
        } catch (ParseException ex) {
            LOG.error("Format birthday string {} error", birthdayStr, ex);
        }
        return 0;
    }

    public static boolean isNoRestrictionRefundRule(SegrpuDO rule) {
        Integer beforeOrAfter = rule.getTimeFlag();
        Integer minTimeO = rule.getMinTime();
        Integer maxTimeO = rule.getMaxTime();
        String minTimeUnit = rule.getMinTimeUnit();
        String maxTimeUnit = rule.getMaxTimeUnit();
        //所有时间都可用的退票规则
        if (minTimeO == null && maxTimeO == null
                && minTimeUnit == null && maxTimeUnit == null
                && beforeOrAfter == null) {
            LOG.info("No restriction refund rule, minTime:{}, minTimeUnit:{}, maxTime:{}, maxTimeUnit:{}, timeFlag:{}", minTimeO, minTimeUnit, maxTimeO, maxTimeUnit, beforeOrAfter);
            return true;
        }
        return false;
    }

    public static boolean isSuitableRefundRule(SegrpuDO rule, Date depDate, Date pnrCancelDate) {
        LOG.debug("Flight depart date is {}, and PNR cancel date is {}", depDate, pnrCancelDate);
        try {
            Integer beforeOrAfter = rule.getTimeFlag();
            LOG.info("Refund rule, before or after:{}", beforeOrAfter);
            Integer minTimeO = rule.getMinTime();
            Integer maxTimeO = rule.getMaxTime();
            String minTimeUnit = rule.getMinTimeUnit();
            String maxTimeUnit = rule.getMaxTimeUnit();
            //所有时间都可用的退票规则
            if (minTimeO == null && maxTimeO == null
                    && minTimeUnit == null && maxTimeUnit == null) {
                if (beforeOrAfter == null) {
                    LOG.info("No restriction refund rule, minTime:{}, minTimeUnit:{}, maxTime:{}, maxTimeUnit:{}, timeFlag:{}", minTimeO, minTimeUnit, maxTimeO, maxTimeUnit, beforeOrAfter);
                    return true;
                }
                boolean isBefore = beforeOrAfter == 0;
                if (isBefore && pnrCancelDate.before(depDate)) {
                    LOG.info("No restriction refund rule before fly, timeFlag:{}", beforeOrAfter);
                    return true;
                } else if (!isBefore && pnrCancelDate.after(depDate)) {
                    LOG.info("No restriction refund rule after fly, timeFlag:{}", beforeOrAfter);
                    return true;
                }
            }
            int minTime = minTimeO;
            int maxTime = maxTimeO;
            boolean isBefore = beforeOrAfter == 0;
            boolean isInRange = isInDateRange(isBefore, minTime, minTimeUnit, maxTime, maxTimeUnit, depDate, pnrCancelDate);
            if (isInRange) {
                return true;
            }
            LOG.info("Refund rule not match");
        } catch (Exception ex) {
            LOG.error("Find suitable refund rule has error", ex);
        }
        return false;
    }

    /**
     * 航前航后判断
     *
     * @param beforeFlight
     * @param minTime
     * @param minTimeUnit
     * @param maxTime
     * @param maxTimeUnit
     * @param originalDate
     * @param destDate
     * @return
     */
    public static boolean isInDateRange(boolean beforeFlight, int minTime, String minTimeUnit, int maxTime, String maxTimeUnit, Date originalDate, Date destDate) {
        LOG.debug("beforeFlight:{}, minTime:{}{}, maxTime:{}{},Fly date is:{}", beforeFlight, minTime, minTimeUnit, maxTime, maxTimeUnit, originalDate);
        RefundTimeUnits minUnit = RefundTimeUnits.getByCode(minTimeUnit);
        RefundTimeUnits maxUnit = RefundTimeUnits.getByCode(maxTimeUnit);
        Date minDate = getDate(originalDate, minTime, minUnit.getUnit(), beforeFlight);
        LOG.debug("Min date is:{}", minDate);
        Date maxDate = getDate(originalDate, maxTime, maxUnit.getUnit(), beforeFlight);
        LOG.debug("Max date is:{}", maxDate);
        boolean isInRange = maxDate.after(destDate) && minDate.before(destDate);
        LOG.debug("{} Date {} is in range: {}", (beforeFlight ? "Before" : "After"), destDate, isInRange);
        return isInRange;
    }

    private static Date getDate(Date originalDate, int time, int timeUnit, boolean beforeOrAfter) {
        LOG.debug(" time:{},{}, Flag date is:{}", time, timeUnit, originalDate);
        Calendar minCalendar = Calendar.getInstance();
        minCalendar.setTime(originalDate);
        if (beforeOrAfter && time > 0) {
            time = -time;
        }
        minCalendar.add(timeUnit, time);
        Date minDate = minCalendar.getTime();
        LOG.debug("Dest date is:{}", minDate);
        return minDate;
    }

    public static Date getCalendarDateTime(Date date, int timeZoneId) throws ParseException {
        String timezone = String.valueOf(timeZoneId);
        if (timeZoneId > 0) {
            timezone = "+" + timeZoneId;
        }
        return getCalendarDateTime(date, timezone);
    }

    public static Date getCalendarDateTime(int timeZoneId) throws ParseException {
        String timezone = String.valueOf(timeZoneId);
        if (timeZoneId > 0) {
            timezone = "+" + timeZoneId;
        }
        return getCalendarDateTime(timezone);
    }

    private static Date getCalendarDateTime(String timeZoneId) throws ParseException {
        return getCalendarDateTime(new Date(), timeZoneId);
    }

    private static Date getCalendarDateTime(Date date, String timeZoneId) throws ParseException {
        LOG.debug("Converting date {} to time zone {} date", date, timeZoneId);
        TimeZone timeZone = TimeZone.getTimeZone("GMT" + timeZoneId);
        LOG.debug("id {}'s timezone id is {}", timeZoneId, timeZone.getID());

        SimpleDateFormat timeZoneFormatter = new SimpleDateFormat("dd-M-yyyy hh:mm:ss a");
        timeZoneFormatter.setTimeZone(timeZone);
        String calendarDateTime = timeZoneFormatter.format(date); // Convert to String first

        SimpleDateFormat formatter = new SimpleDateFormat("dd-M-yyyy hh:mm:ss a");
        return formatter.parse(calendarDateTime);
    }

}
